﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using DomainDriver.DomainModeling.Constraints;
using DomainDriver.DomainModeling.DataProviders;
using DomainDriver.DomainModeling.DomainModels;
using DomainDriver.DomainModeling.DomainObjects;
using DomainDriver.DomainModeling.Exceptions;
using DomainDriver.DomainModeling.Repositories;

namespace DomainDriver.DomainModeling.GenericUnitTesting.Constraints
{
    public abstract class FixedValuesConstraintTestFixture<DOMAIN_MODEL, KEY, KEYED_DOMAIN_OBJECT> : ConstraintTestFixture<DOMAIN_MODEL, FixedValuesConstraint<KEY, KEYED_DOMAIN_OBJECT>>
        where DOMAIN_MODEL : class, IDomainModel
        where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>
    {
        public FixedValuesConstraintTestFixture(DataSourcePersistenceType persistenceType)
            : base(persistenceType)
        {
            // do nothing
        }

        protected virtual IRepository<KEY, KEYED_DOMAIN_OBJECT> FixedValuesRepository
        {
            get { return DomainModel.GetRepository<KEY, KEYED_DOMAIN_OBJECT>(); }
        }

        protected abstract int GetNumberOfExpectedObjectsLoadedInSetup();
        protected abstract KEYED_DOMAIN_OBJECT CreateDomainObjectForFalseEnumValue();
        protected abstract void UpdateDomainObject(KEYED_DOMAIN_OBJECT domainObject, ref bool objectCanBeUpdated);

        [Test]
        public virtual void VerifyConstraintSetup_POSITIVE()
        {
            SaveAndReloadDomainModel();

            int expectedNumberOfObjects = GetNumberOfExpectedObjectsLoadedInSetup();
            int actualNumberOfObjects = FixedValuesRepository.Count();

            Assert.AreEqual(expectedNumberOfObjects, actualNumberOfObjects);
        }

        [Test]
        [ExpectedException(typeof(DomainObjectManagementException))]
        public virtual void VerifyConstraintOnAddingDomainObject_NEGATIVE()
        {
            KEYED_DOMAIN_OBJECT domainObject = CreateDomainObjectForFalseEnumValue();

            FixedValuesRepository.Add(domainObject);

            SaveAndReloadDomainModel();

            Assert.IsTrue(FixedValuesRepository.Exists(domainObject.Key));
        }

        [Test]
        [ExpectedException(typeof(DomainObjectManagementException))]
        public virtual void VerifyConstraintOnUpdatingDomainObject_NEGATIVE()
        {
            bool objectCanBeUpdated = true;
            KEYED_DOMAIN_OBJECT originalObject = default(KEYED_DOMAIN_OBJECT);
            KEYED_DOMAIN_OBJECT copiedObject = default(KEYED_DOMAIN_OBJECT);
            KEYED_DOMAIN_OBJECT reloadedObject = default(KEYED_DOMAIN_OBJECT);

            KEY firstKey = FixedValuesRepository.FindKeys().First<KEY>();

            originalObject = FixedValuesRepository.Read(firstKey);
            copiedObject = originalObject.Copy();
            UpdateDomainObject(originalObject, ref objectCanBeUpdated);
            if (objectCanBeUpdated)
            { Assert.AreNotEqual(copiedObject, originalObject); }
            else
            { Assert.AreEqual(copiedObject, originalObject); }

            FixedValuesRepository.Update(originalObject);

            SaveAndReloadDomainModel();

            reloadedObject = FixedValuesRepository.Read(firstKey);
            Assert.AreEqual(reloadedObject, originalObject);
        }

        [Test]
        [ExpectedException(typeof(DomainObjectManagementException))]
        public virtual void VerifyConstraintOnRemovingDomainObject_NEGATIVE()
        {
            KEY firstKey = FixedValuesRepository.FindKeys().First<KEY>();

            FixedValuesRepository.Remove(firstKey);

            SaveAndReloadDomainModel();

            Assert.IsFalse(FixedValuesRepository.Exists(firstKey));
        }
    }
}